﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using EpiNEXT.Core.Fields;

namespace EpiNEXT.Core.Collections
{
    public class FieldCollection : ObservableCollection<IField>
    {
        #region Members
        private ObservableCollection<TextBoxField> _textFields = new ObservableCollection<TextBoxField>();
        private ObservableCollection<IDataField> _dataFields = new ObservableCollection<IDataField>();
        private ObservableCollection<MirrorField> _mirrorFields = new ObservableCollection<MirrorField>();
        private ObservableCollection<NumberField> _numberFields = new ObservableCollection<NumberField>();
        private Dictionary<string, IField> _master = new Dictionary<string, IField>(StringComparer.OrdinalIgnoreCase);
        #endregion // Members

        #region Properties
        /// <summary>
        /// Type Name
        /// </summary>
        /// <param name="name">Name</param>
        /// <returns>NamedObjectCollection</returns>
        public IField this[string name]
        {
            get
            {
                return _master[name];
            }
        }

        /// <summary>
        /// Type Name
        /// </summary>
        /// <param name="name">Name</param>
        /// <returns>NamedObjectCollection</returns>
        public IField this[Guid id]
        {
            get
            {
                foreach (KeyValuePair<string, IField> kvp in this._master)
                {
                    if (kvp.Value.FieldId == id) return kvp.Value;
                }
                throw new IndexOutOfRangeException();
            }
        }

        /// <summary>
        /// Returns the collection of Text Fields.
        /// </summary>
        public ObservableCollection<TextBoxField> TextFields
        {
            get
            {
                return this._textFields;
            }
        }

        /// <summary>
        /// Returns the collection of Mirror Fields.
        /// </summary>
        public ObservableCollection<MirrorField> MirrorFields
        {
            get
            {
                return this._mirrorFields;
            }
        }

        /// <summary>
        /// Returns the collection of Number Fields.
        /// </summary>
        public ObservableCollection<NumberField> NumberFields
        {
            get
            {
                return this._numberFields;
            }
        }

        /// <summary>
        /// Returns the collection of data fields.
        /// </summary>
        public ObservableCollection<IDataField> DataFields
        {
            get
            {
                return this._dataFields;
            }
        }

        /// <summary>
        /// Gets the form this collection belongs to
        /// </summary>
        public DataEntryInstrument Form { get; set; }
        #endregion // Properties

        #region Methods
        public virtual bool Contains(string fieldName)
        {
            return _master.ContainsKey(fieldName.ToLower());
        }

        public virtual bool Contains(Guid id)
        {
            foreach (KeyValuePair<string, IField> kvp in this._master)
            {
                if (kvp.Value.FieldId == id) return true;
            }
            return false;
        }

        protected override void InsertItem(int index, IField item)
        {
            //return;

            base.InsertItem(index, item);

            #region Input Validation
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            #endregion // Input Validation

            _master.Add(item.Name, item);

            if (item is NumberField)
            {
                NumberFields.Add(item as NumberField);
            }
            if (item is TextBoxField)
            {
                TextFields.Add(item as TextBoxField);
            }
            if (item is MirrorField)
            {
                MirrorFields.Add(item as MirrorField);
            }
            if (item is IDataField)
            {
                DataFields.Add(item as IDataField);
            }

            UpdatePageCollections();
        }

        protected override void ClearItems()
        {
            base.ClearItems();
            _master.Clear();

            NumberFields.Clear();
            TextFields.Clear();
            MirrorFields.Clear();
            DataFields.Clear();

            UpdatePageCollections();
        }

        protected override void RemoveItem(int index)
        {
            IField fieldToRemove = this[index];
            _master.Remove(fieldToRemove.Name);
            base.RemoveItem(index);

            if (fieldToRemove is NumberField)
            {
                NumberFields.Remove(fieldToRemove as NumberField);
            }
            if (fieldToRemove is TextBoxField)
            {
                TextFields.Remove(fieldToRemove as TextBoxField);
            }
            if (fieldToRemove is MirrorField)
            {
                MirrorFields.Remove(fieldToRemove as MirrorField);
            }
            if (fieldToRemove is IDataField)
            {
                DataFields.Remove(fieldToRemove as IDataField);
            }
            UpdatePageCollections();
        }

        protected override void SetItem(int index, IField item)
        {
            #region Input Validation
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            #endregion // Input Validation

            IField fieldToChange = this[index];
            _master.Remove(fieldToChange.Name);

            _master.Add(item.Name, item);

            base.SetItem(index, item);
        }

        private void UpdatePageCollections()
        {
            if (this.Form is Form)
            {
                foreach (EpiNEXT.Core.Page page in (this.Form as Form).Pages)
                {
                    page.UpdateFields();
                }
            }
        }
        #endregion // Methods
    }
}
